package cn.yinuo.website.common.security;

import cn.yinuo.website.common.config.ApplicationConfigurer;
import cn.yinuo.website.user.entity.User;
import com.google.common.collect.Maps;
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Base64;
import java.util.Date;
import java.util.Map;

@Configuration
public class JavaWebToken {

    private static Logger log = LoggerFactory.getLogger(JavaWebToken.class);

    /** 应用配置 */
    @Autowired
    private ApplicationConfigurer applicationConfigurer;

    /**用户名*/
    private static final String  CLAIM_KEY_USER_ID = "userId";
    /**创建时间*/
    private static final String  CLAIM_KEY_CREATED = "created";

    /** 创建token */
    public String createJwt(User userDetail) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        Date now = new Date();
        Map<String, Object> info = Maps.newHashMap();
        info.put(CLAIM_KEY_USER_ID, userDetail.getId());
        info.put(CLAIM_KEY_CREATED, now);
        Date expire = new Date(
                LocalDateTime.now().plusHours(3).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        JwtBuilder builder = Jwts.builder().setId("") // JWT_ID
                //.setAudience("") 接受者
                .setClaims(info) // 自定义属性
                .setSubject(userDetail.getUsername()) // 主题
//				.setIssuer() // 签发者
                .setIssuedAt(now) // 签发时间
                .setNotBefore(now) // 失效时间
                .setExpiration(expire) // 过期时间
                .signWith(signatureAlgorithm, generalKey()); // 签名算法以及密匙
        return builder.compact();
    }

    /** 解析 (权限未复制) 会抛出异常*/
    public User parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        User user = null;
        try {
            Claims claims =  Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
            if (isTokenExpired(claims)) throw new RuntimeException("Token已过期");
            user = new User().setSignName(claims.getSubject()).setId(claims.get(CLAIM_KEY_USER_ID,Integer.class).longValue());
        } catch (ExpiredJwtException e) {
            throw e;
        } catch (SignatureException e) {
            throw new RuntimeException("签名校验失败");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return user;
    }

    /**token是否过期*/
    private  boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }

    /** 密匙 */
    private SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(applicationConfigurer.getJwtSecertKey());
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
}